package com.sys.basics.config.shiro;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sys.basics.entity.SysResource;
import com.sys.basics.entity.SysUser;
import com.sys.basics.service.SysResourceService;
import com.sys.basics.service.SysUserService;
import com.sys.basics.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.List;


@Slf4j
public class MyShiroRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Autowired
    @Lazy
    private SysResourceService sysResourceService;

    /**
     * @param principalCollection
     * @return
     * @author: ares
     * @date: 2021/9/24 21:27
     * @description: 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SysUser userInfo = ShiroUtils.getUserInfo();
        SysUser currentUserInfo = sysUserService.getCurrentUserInfoWithRoleAndOrg(userInfo.getId());
        log.info("shiro 授权用户: {}", JSONUtil.parse(currentUserInfo));
        List<SysResource> resources = sysResourceService.getListByRoleId(currentUserInfo.getRoleInfo().getId());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if(ObjectUtil.isNotNull(resources)){
            for (SysResource resource: resources){
                info.addStringPermission(resource.getPerms());
            }
        }
        return info;
    }


    /**
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     * @author: ares
     * @date: 2021/9/24 21:26
     * @description: 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String userId = (String) authenticationToken.getPrincipal();
        log.info("shiro认证用id: {}", userId);
        SysUser currentUser = sysUserService.getById(Long.valueOf(userId));
        if (ObjectUtil.isNull(currentUser)) {
            throw new UnknownAccountException();
        }
        String salt = currentUser.getSalt();
        return new SimpleAuthenticationInfo(currentUser, currentUser.getPassword(), new MyByteSource(salt), getName());
    }

    /**
     * @author: ares
     * @date: 2021/11/10 11:15
     * @description: doGetAuthenticationInfo方法创建SimpleAuthenticationInfo时传入的principal是SysUser时,
     * 退出登录调用subject.logout()清除不掉认证缓存信息
     */
    @Override
    protected void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        if (ObjectUtil.isNotNull(principals)) {
            Cache<Object, AuthenticationInfo> cache = getAuthenticationCache();
            if(ObjectUtil.isNull(cache)){
                super.clearCachedAuthenticationInfo(principals);
            }else {
                SysUser sysUser = (SysUser) principals.getPrimaryPrincipal();
                cache.remove(sysUser.getId());
            }
        }
    }

    /**
     * @author: ares
     * @date: 2021/11/10 13:55
     * @description: 动态更新缓存的认证信息 ,清理授权信息(权限认证时重新授权)
     */
    public void updateAuthenticationAndAuthorization(SysUser userInfo){
        ShiroUtils.updatePrincipal(userInfo);
        super.clearCachedAuthorizationInfo(ShiroUtils.getSubject().getPrincipals());
    }
}
